import open3d as o3d
import numpy as np

voxel_size = 0.005 # 体素边长
radius = 0.01 # 体素下采集 —— 邻域搜索半径
max_nn = 40 # 体素下采集 —— 最大找的点数
depth = 20 # 表面重建深度

ply_point_cloud_path = r"D:\AllCode\3D Point Cloud\Open3D\Notes\Part 3 Vertex normal estimation\Try\bun_zipper.ply"
pcd = o3d.io.read_point_cloud(ply_point_cloud_path)
print(pcd)
print(np.asarray(pcd))

print(f"边长为{voxel_size}的体素下采集")
downpcd = pcd.voxel_down_sample(voxel_size = voxel_size)
print(downpcd)

# 法向估计
print("法向估计")
downpcd.estimate_normals(
    search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=radius, max_nn=max_nn))

# 统一法向朝向
downpcd.orient_normals_towards_camera_location(camera_location=[0, 0, 0])

# 表面重建
mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
    downpcd,  
    depth=8   
)

# 后处理：过滤1%最低密度的顶点
vertices_to_remove = densities < np.quantile(densities, 0.02)
mesh.remove_vertices_by_mask(vertices_to_remove)

# 拉普拉斯平滑
mesh.filter_smooth_laplacian(number_of_iterations=5)

# 填充小缺口
# mesh.fill_holes()  # 有时候就很奇怪，这也不支持，那也不支持

# 重新计算网格法向
mesh.compute_vertex_normals()

# 显示
o3d.visualization.draw_geometries([mesh], point_show_normal=False)

# 最后的显示结果就是，基本实现了重建，但是还是有很多细节的丢失 